/** cmd_buf datavew */
function read_int8(cmd_buf, offset) {
    // return cmd_buf.readInt8(offset);
    return cmd_buf.getInt8(offset);
}

function write_int8(cmd_buf, offset, value) {
    // cmd_buf.writeInt8(value, offset);
    cmd_buf.setInt8(offset, value);
}

function read_int16(cmd_buf, offset) {
    return cmd_buf.getInt16(offset, true);
}

function write_int16(cmd_buf, offset, value) {
    cmd_buf.setInt16(offset, value, true);
}

function read_int32(cmd_buf, offset) {
    return cmd_buf.getInt32(offset, true);
}

function write_int32(cmd_buf, offset, value) {
    cmd_buf.setInt32(offset, value, true);
    // cmd_buf.writeInt32LE(value, offset);
}

function read_uint32(cmd_buf, offset) {
    return cmd_buf.getUint32(offset);
}

function write_uint32(cmd_buf, offset, value) {
    cmd_buf.setUint32(offset, value);
}

function read_str(cmd_buf, offset, byte_len) {
    // return cmd_buf.toString(`utf8`, offset, offset + byte_len);
    return cmd_buf.read_utf8(offset, byte_len);
}

function write_str(cmd_buf, offset, str) {
    // cmd_buf.write(str, offset);
    cmd_buf.write_utf8(offset, str);
}

function read_float(cmd_buf, offset) {
    // return cmd_buf.readFloatLE(offset);
    return cmd_buf.getFloat32(offset, true);
}

function write_float(cmd_buf, offset, value) {
    // cmd_buf.writeFloatLE(value, offset);
    cmd_buf.setFloat32(offset, value, true);
}

function alloc_buffer(total_len) {
    // return Buffer.allocUnsafe(total_len);
    let buf = new ArrayBuffer(total_len);
    let dataview = new DataView(buf);
    return dataview;
}

function write_cmd_header_inbuf(cmd_buf, stype, ctype) {
    write_int16(cmd_buf, 0, stype);
    write_int16(cmd_buf, 2, ctype);
    write_uint32(cmd_buf, 4, 0);
    return proto_tools.header_size;
}

function write_prototype_inbuf(cmd_buf, proto_type){
    write_int16(cmd_buf, 8, proto_type);
}

/** 性能考虑，自己传长度 */
function write_str_inbuf(cmd_buf, offset, str, byte_len){
    write_int16(cmd_buf, offset, byte_len);
    offset += 2;

    write_str(cmd_buf, offset, str);
    offset += byte_len;
    return offset;
}

/** 返回 str, offset */
function read_str_inbuf(cmd_buf, offset){
    let byte_len = read_int16(cmd_buf, offset);
    offset += 2;
    let str = read_str(cmd_buf, offset, byte_len);
    offset += byte_len;

    return [str, offset]
}

function decoded_empty_cmd(cmd_buf) {
    let cmd = {};
    cmd[0] = read_int16(cmd_buf, 0);
    cmd[1] = read_int16(cmd_buf, 2);
    cmd[2] = null;
    return cmd;
}

function encoded_empty_cmd(stype, ctype, body) {
    let cmd_buf = alloc_buffer(proto_tools.header_size);
    write_cmd_header_inbuf(cmd_buf, stype, ctype);
    return cmd_buf;
}

function encode_status_cmd(stype, ctype, status) {
    let cmd_buf = alloc_buffer(proto_tools.header_size + 2);
    write_cmd_header_inbuf(cmd_buf, stype, ctype);
    write_int16(cmd_buf, proto_tools.header_size, status);
    return cmd_buf;
}

function decode_status_cmd(cmd_buf){
    let cmd = {};
    cmd[0] = read_int16(cmd_buf, 0);
    cmd[1] = read_int16(cmd_buf, 2);
    cmd[2] = read_int16(cmd_buf, proto_tools.header_size);
    
    return cmd;
}

function encode_str_cmd(stype, ctype, str){
    let byte_len = str.utf8_byte_len();
    let total_len = proto_tools.header_size + 2 + byte_len;
    let cmd_buf = alloc_buffer(total_len);
    let offset = write_cmd_header_inbuf(cmd_buf, stype, ctype);
    offset = write_str_inbuf(cmd_buf, offset, str, byte_len);

    return cmd_buf;
}

function decode_str_cmd(cmd_buf){
    let cmd = {};
    cmd[0] = read_int16(cmd_buf, 0);
    cmd[1] = read_int16(cmd_buf, 2);
    let ret = read_str_inbuf(cmd_buf, proto_tools.header_size);
    cmd[2] = ret[0];
    return cmd;
}

const proto_tools = {
    header_size: 10, // stype: 2, ctype: 2, header: 4, prototype: 2
    /** 元操作 */
    read_int8: read_int8,
    write_int8: write_int8,
    read_int16: read_int16,
    write_int16: write_int16,
    read_int32: read_int32,
    write_int32: write_int32,

    read_float: read_float,
    write_float: write_float,

    read_uint32: read_uint32,
    write_uint32: write_uint32,

    alloc_buffer: alloc_buffer,

    /** 通用操作 */
    write_cmd_header_inbuf, write_cmd_header_inbuf,
    write_prototype_inbuf: write_prototype_inbuf,
    read_str_inbuf: read_str_inbuf,
    write_str_inbuf: write_str_inbuf,

    /** 模板编码解码器 */
    encode_str_cmd: encode_str_cmd,
    encode_status_cmd: encode_status_cmd,
    encoded_empty_cmd: encoded_empty_cmd,

    decode_str_cmd: decode_str_cmd,
    decode_status_cmd: decode_status_cmd,
    decoded_empty_cmd: decoded_empty_cmd
};

module.exports = proto_tools;